package com.tjbaobao.mp4lib.mp4info;


import com.tjbaobao.mp4lib.info.CustomData;
import com.tjbaobao.mp4lib.info.Mp4InfoConstant;
import com.tjbaobao.mp4lib.tools.ByteTools;
import com.tjbaobao.mp4lib.tools.FileTools;
import com.tjbaobao.mp4lib.tools.HexConvertTools;
import com.tjbaobao.mp4lib.info.CustomData.Data;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;

/**
 * MP4切割器
 * @author TJbaobao
 *
 */
public class Mp4Segmentation {
	public static final long SUB_SIZE = 1024*1024;
	private static final String DEF_CHARSET_NAME= "iso8859-1";
	private long indexMDat ;
	private long sizeMDat;
	private long sizeFileMP4,sizeHead,sizeFoot,indexHead,indexFoot;
	
	private OnProgressListener onProgressListener ;
	private long readedSize = 0;
	
	public ArrayList<String> segmentation(String pathMP4,String outFolder,long subSize,CustomData customData)
	{
		ArrayList<String> pathList = new ArrayList<String>();
		File fileMP4 = new File(pathMP4);
		if(fileMP4.exists())
		{
			if(outFolder==null)
			{
				outFolder = fileMP4.getParent();
			}
			sizeFileMP4 = fileMP4.length();
			ArrayList<Long> positionList = FileTools.indexOf(0,sizeFileMP4,"mdat",pathMP4);
			if(positionList!=null&&positionList.size()>0)
			{
				indexMDat = positionList.get(0)-4;
				//获取各个部位的信息
				byte[] bytesSizeMDat = FileTools.Reader.readFileToBytes(indexMDat,4,pathMP4) ;
				if(bytesSizeMDat!=null)
				{
					sizeMDat= HexConvertTools.bytesToInt(bytesSizeMDat,0);
					if(sizeMDat>0)
					{
						if(sizeMDat==1)
						{
							byte[] bytesLargesizeMDat = FileTools.Reader.readFileToBytes(indexMDat+8,8,pathMP4) ;
							if(bytesLargesizeMDat==null)
							{
								pathList.add(pathMP4);
								return pathList;
							}
							sizeMDat = HexConvertTools.bytesToLong(bytesLargesizeMDat);
						}
						sizeHead = indexMDat;
						sizeFoot = sizeFileMP4 - (indexMDat+sizeMDat);
						indexHead = 0;
						indexFoot = indexMDat+sizeMDat;
						byte[] bytesHead = FileTools.Reader.readFileToBytes(indexHead, (int) sizeHead, pathMP4);
						byte[] bytesFoot = FileTools.Reader.readFileToBytes(indexFoot, (int) sizeFoot, pathMP4);
						byte[] bytesMdatSize = createBoxBytes(Mp4InfoConstant.HEAD_MDAT_SIZE_NAME,HexConvertTools.intToByteArray((int) sizeMDat));
						byte[] bytesTjbb = createTjbbBytes(customData, bytesHead, bytesFoot,bytesMdatSize);
						String pathTjbb = outFolder+"/"+FileTools.changeSuffix(fileMP4.getName(), "")+"tjbb";
						FileTools.delFileIfExists(pathTjbb);
						FileTools.Writer.writeFile(bytesTjbb, pathTjbb);
						pathList.add(pathTjbb);
						readedSize+=sizeHead+sizeFoot;
						onProgress(readedSize,sizeFileMP4);
						ArrayList<String> listMDat = FileTools.cupFile(indexMDat, sizeMDat, (int) subSize, pathMP4,outFolder, "dat",new OnProgressListener() {
							
							@Override
							public void onProgress(float readed, float size) {
								readedSize+=readed;
								Mp4Segmentation.this.onProgress(readedSize,sizeFileMP4);
							}
						});
						for(String path:listMDat)
						{
							pathList.add(path);
						}
						return pathList;
					}
				}
			}
		}
		else
		{
			System.out.println("文件不存在");
		}
		
		return null;
	}
	
	
	private byte[] createTjbbBytes(CustomData customData,byte[] headBytes,byte[] footBytes,byte[] mdatSizeBytes)
	{
		
		byte[] customBytes = customData==null?null: createCustomBytes(customData);
		headBytes = headBytes==null?null: createTjbbHeadBytes(headBytes);
		footBytes = footBytes==null?null: createTjbbFootBytes(footBytes);
		int bufSize = getBytesLength(customBytes)+getBytesLength(headBytes)+getBytesLength(footBytes)+getBytesLength(mdatSizeBytes);
		ByteBuffer buffer = ByteBuffer.allocate(bufSize);
		if(customData!=null)
		{
			buffer.put(customBytes);
		}
		if(headBytes!=null)
		{
			buffer.put(headBytes);
		}
		if(footBytes!=null)
		{
			buffer.put(footBytes);
		}
		if(mdatSizeBytes!=null)
		{
			buffer.put(mdatSizeBytes);
		}
		return createBoxBytes(Mp4InfoConstant.HEAD_NAME,buffer.array());
	}
	
	private byte[] createTjbbHeadBytes(byte[] headBytes)
	{
		return createBoxBytes(Mp4InfoConstant.HEAD_HEAD_NAME,headBytes);
	}
	
	private byte[] createTjbbFootBytes(byte[] footBytes)
	{
		return createBoxBytes(Mp4InfoConstant.HEAD_FOOT_NAME,footBytes);
	}
	
	
	private CustomData setCustom(CustomData customData)
	{
		if(customData==null)
		{
			return null;
		}
		ArrayList<CustomData.Data> customDataList = customData.getCustomDataList();
		for(CustomData.Data data:customDataList)
		{
			if(!(data.getDataType()==CustomData.getDataTypeOrder()))
			{
				try {
					switch(data.getDataType())
					{
					case CustomData.DATA_TYPE_HEAD_INDEX:
						data.setDataByte(Long.toHexString(indexHead).getBytes(DEF_CHARSET_NAME));
						break;
					case CustomData.DATA_TYPE_HEAD_SIZE:
						data.setDataByte(Long.toHexString(indexHead).getBytes(DEF_CHARSET_NAME));
						break;
					case CustomData.DATA_TYPE_MDAT_INDEX:
						data.setDataByte(Long.toHexString(indexMDat).getBytes(DEF_CHARSET_NAME));
						break;
					case CustomData.DATA_TYPE_MDAT_SIZE:
						data.setDataByte(Long.toHexString(sizeMDat).getBytes(DEF_CHARSET_NAME));
						break;
					case CustomData.DATA_TYPE_FOOT_INDEX:
						data.setDataByte(Long.toHexString(indexFoot).getBytes(DEF_CHARSET_NAME));
						break;
					case CustomData.DATA_TYPE_FOOT_SIZE:
						data.setDataByte(Long.toHexString(sizeFoot).getBytes(DEF_CHARSET_NAME));
						break;
					default :
							
						break;
					}
				}
				catch (UnsupportedEncodingException e) 
				{
					e.printStackTrace();
				}
				
			}
		}
		
		return null;
		
	}
	
	private byte[] createCustomBytes(CustomData customData)
	{
		setCustom(customData);
		byte[] nameBytes = createCustomNameBytes(customData);
		byte[] dataBytes = createCustomDataBytes(customData);
		int bufferSize = getBytesLength(nameBytes)+getBytesLength(dataBytes);
		ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
		buffer.put(nameBytes);
		buffer.put(dataBytes);
		
		return createBoxBytes(Mp4InfoConstant.HEAD_CUSTOM_NAME,buffer.array());
	}
	
	private byte[] createCustomNameBytes(CustomData customData)
	{
		int bufferSize = 0;
		
		ArrayList<Data> customDataList = customData.getCustomDataList();
		for (Data data : customDataList) {
			byte[] nameBytes = createCustomNameItemBytes(data.getDataName());
			if(nameBytes!=null)
			{
				bufferSize+=nameBytes.length;
			}
		}
		ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
		for (Data data : customDataList) {
			byte[] nameBytes = createCustomNameItemBytes(data.getDataName());
			if(nameBytes!=null)
			{
				buffer.put(nameBytes);
			}
			else
			{
				buffer.put(new byte[0]);
			}
		}
		return createBoxBytes(Mp4InfoConstant.HEAD_CUSTOM_NAME_NAME,buffer.array());
	}
	
	private byte[] createCustomNameItemBytes(String name)
	{
		try {
			if(name!=null)
			{
				return createBoxBytes(Mp4InfoConstant.HEAD_CUSTOM_NAME_VALUE_NAME, name.getBytes(DEF_CHARSET_NAME));
			}
			else
			{
				return null;
			}
		}
		catch (UnsupportedEncodingException e) {
		e.printStackTrace();
		}
		return null;
	}
	
	private byte[] createCustomDataBytes(CustomData customData)
	{
		int bufferSize = 0;
		
		ArrayList<Data> customDataList = customData.getCustomDataList();
		for (Data data : customDataList) {
			byte[] dataBytes = createCustomDataItemBytes(data);
			if(dataBytes!=null)
			{
				bufferSize+=dataBytes.length;
			}
			
		}
		ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
		for (Data data : customDataList) {
			byte[] dataBytes = createCustomDataItemBytes(data);
			if(dataBytes!=null)
			{
				buffer.put(dataBytes);
			}
			else
			{
				buffer.put(new byte[0]);
			}
		}
		return createBoxBytes(Mp4InfoConstant.HEAD_CUSTOM_DATA_NAME,buffer.array());
	}
	
	private byte[] createCustomDataItemBytes(Data data)
	{
		if(data!=null)
		{
			if(data.getDataName()!=null&&data.getDataByte()!=null)
			{
				return createBoxBytes(data.getDataName(), data.getDataByte());
			}
			else
			{
				return null;
			}
		}
		else
		{
			return null;
		}
	}
	
	private byte[] createBoxBytes(String name,byte[] dataByte)
	{
		try {
			int nameSize = name.getBytes(DEF_CHARSET_NAME).length;
			int dataSize = dataByte.length;
			int sizeSize = 4;
			if (dataSize > Integer.MAX_VALUE) {
				sizeSize = 8;
			}
			int customSize = nameSize+sizeSize+dataSize;
			byte[] byteData = new byte[customSize];
			byte[] nameByte = name.getBytes(DEF_CHARSET_NAME);
			byte[] sizeByte = HexConvertTools.intToByteArray(customSize);
			ByteTools.copyBytes(byteData,nameByte, 0, nameSize);
			ByteTools.copyBytes(byteData,sizeByte, nameSize, sizeSize);
			ByteTools.copyBytes(byteData,dataByte, nameSize+sizeSize, dataSize);
			
			return byteData;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private int getBytesLength(byte[] bytes)
	{
		return bytes==null?0:bytes.length;
	}

	private void onProgress(long readed,long size)
	{
		if(onProgressListener!=null)
		{
			onProgressListener.onProgress(readed, size);
		}
	}
	
	public OnProgressListener getOnProgressListener() {
		return onProgressListener;
	}

	public void setOnProgressListener(OnProgressListener onProgressListener) {
		this.onProgressListener = onProgressListener;
	}


	public static String getDefCharsetName() {
		return DEF_CHARSET_NAME;
	}


	public long getIndexMDat() {
		return indexMDat;
	}


	public long getSizeMDat() {
		return sizeMDat;
	}


	public long getSizeFileMP4() {
		return sizeFileMP4;
	}


	public long getSizeHead() {
		return sizeHead;
	}


	public long getSizeFoot() {
		return sizeFoot;
	}


	public long getIndexHead() {
		return indexHead;
	}


	public long getIndexFoot() {
		return indexFoot;
	}
	
	

}
